package com.awesome.socketdemo.udp;

import com.teeim.ticommon.init.TiCommon;
import com.teeim.ticommon.ticleaner.TiCleaner;
import com.teeim.ticommon.ticonnection.TiConnection;
import com.teeim.ticommon.ticonnection.TiEventSocketAccept;
import com.teeim.ticommon.ticonnection.TiEventSocketConnect;
import com.teeim.ticommon.ticonnection.TiUdpSocket;
import com.teeim.ticommon.timessage.*;
import com.teeim.ticommon.titrace.TiTraceLevel;
import com.teeim.ticommon.titrace.TiTracer;
import com.teeim.ticommon.titransaction.TiTransaction;
import com.teeim.ticommon.titransaction.TiTransactionReceived;

public class UdpClient {
    private static final TiTracer TRACER = TiTracer.create(UdpClient.class);

    private volatile boolean mStopBroadcast = false;

    private class Broadcast implements Runnable {
        private String mBroadcastAddress;
        private int mPort;
        private String mSSID;
        private String mPSK;
        private String mNav;

        Broadcast(String broadcastAddress, int port, String ssid, String psk, String nav) {
            mBroadcastAddress = broadcastAddress;
            mPort = port;
            mSSID = ssid;
            mPSK = psk;
            mNav = nav;
        }

        @Override
        public void run() {
            TiUdpSocket socket = new TiUdpSocket(2, 32768, 30);
            socket.connect(mBroadcastAddress, mPort, new TiEventSocketConnect() {
                @Override
                public void connected(TiConnection conn) {
                    while (!mStopBroadcast) {
                        TiRequest req = new TiRequest(TiRequestMethod.Data);
                        req.addHeader(new TiHeader(TiHeaderType.Key, mSSID));
                        req.addHeader(new TiHeader(TiHeaderType.Credential, mPSK));
                        req.addHeader(new TiHeader(TiHeaderType.Description, mNav));
                        TiTransaction trans = conn.createTransaction(req);
                        trans.sendRequest();

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    conn.close();
                    socket.dispose();
                    System.out.println("Broadcast is stopped.");
                }

                @Override
                public void connectFailed() {
                    System.err.println("Connect failed.");
                }
            }, true);
        }
    }

    private class Receive implements Runnable {
        @Override
        public void run() {
            if (TRACER.InfoAvailable()) {
                TRACER.Info("Listen 0.0.0.0:8889");
            }
            TiUdpSocket socket = new TiUdpSocket(2, 32768, 30);
            socket.listen("0.0.0.0", 8889, new TiEventSocketAccept() {
                @Override
                public void accept(TiConnection conn) {
                    conn.setEvent(new TiTransactionReceived() {
                        @Override
                        public void transactionCreated(TiConnection tiConnection, TiTransaction trans) {
                            TiRequest req = trans.getRequest();
                            if (TiRequestMethod.Data == req.getMethod()) {
                                if (0xFF == req.getHeader(TiHeaderType.Event, -1)) {
                                    mStopBroadcast = true;
                                    trans.sendResponse(new TiResponse(TiResponseCode.OK));
                                    System.out.println("Received request, stop broadcast.");
                                    tiConnection.close();
                                    socket.dispose();
                                    TiCleaner.dispose();
                                }
                            }
                        }

                        @Override
                        public void disconnected(TiConnection conn) {
                            System.out.println("disconnected");
                            socket.dispose();
                            TiCleaner.dispose();
                        }
                    });
                }
            });
        }
    }

    public static void main(String[] args) {
        if (args.length != 5) {
            System.err.println("Usage: <Broadcast IP> <Receive Port> <SSID> <psk> <navigator>");
            return ;
        }

        TiCommon.initialize(TiTraceLevel.Debug, 20);

        String broadcastAddr = args[0];
        int port = Integer.parseInt(args[1]);
        String ssid = args[2];
        String psk = args[3];
        String nav = args[4];

        if (TRACER.DebugAvailable()) {
            TRACER.Debug("Broadcast Address: " + broadcastAddr);
            TRACER.Debug("Broadcast Port: " + port);
            TRACER.Debug("SSID: " + ssid);
            TRACER.Debug("PSK: " + psk);
            TRACER.Debug("Navigator: " + nav);
        }

        UdpClient client = new UdpClient();
        Thread broadcastThread = new Thread(client.new Broadcast(broadcastAddr, port, ssid, psk, nav));
        Thread receiveThread = new Thread(client.new Receive());

        receiveThread.start();
        broadcastThread.start();

        try {
            broadcastThread.join();
            System.out.println("Broadcast thread quit.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            receiveThread.join();
            System.out.println("Receive thread quit.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
